<?php
namespace dreamphp;

class DreamPHP
{
	public static function run()
	{
		//这是一个教学级MVC框架，我们就不使用容器、门面、依赖注入、参数绑定等等功能了
		//dispatch是一个路由分发，我们这里使用pathinfo方式访问，也不做兼容性检测了，访问方式使用域名/入口文件/模块/控制器/方法方式访问例如：http://mvc.cn/index.php/index/index/index
		self::dispatch();
	}
	
	private static function dispatch()
	{
		//使用pathinfo参数获取模块、控制器、方法名字，如果没有pathinfo参数则使用默认的index模块，index控制器，index方法；在psr规范的基础上，我们规定模块都是用小写，控制器首字母大写，方法小写
		$pathinfo = $_SERVER['PATH_INFO'] ?? 'index/Index/index';
		//去掉pathinfo俩边的/，把字符串变成数组
		$pathinfoArray = explode('/', trim($pathinfo, '/'));
		//获取模块名字，就是$pathinfoArray数组中的第一个，如果不为空则取出来，如果是空的则设置为index
		$moduleName = empty($pathinfoArray[0]) ? 'index' : strtolower($pathinfoArray[0]);
		//获取控制器的名字，$pathinfoArray数组中的第二个，只能是设置了或者没有，不理解的，自己测试几次就理解了
		$controllerName = isset($pathinfoArray[1]) ? ucfirst(strtolower($pathinfoArray[1])) : 'Index';
		//获取方法的名字，跟控制器一样
		$actionName = isset($pathinfoArray[2]) ? strtolower($pathinfoArray[2]) : 'index';
		//下面我们分别检测模块控制器方法是否存在,我们没有自定义异常类，就用PHP内置的异常类，当然你也可以直接输出错误信息
		$module = DREAM_PATH . 'application/' . $moduleName;
		if (file_exists($module)) {
			//如果模块存在，我们就检测控制器类是否存在，我们引入了composer自动加载，所以使用命名空间即可检测
			$controller = "app\\" . $moduleName . "\\controller\\" . $controllerName;
			if (class_exists($controller)) {
				//这个时候判断控制器类存在，则对类进行实例化，我们可以直接new，也可以用PHP的高级特性，反射机制
				//反射机制
				//$reflect是类的信息
				$reflect = new \ReflectionClass($controller);
				//$controllerClass是控制器类的实例化，跟我们new是一样的，为了方便我们在控制器里面直接对模板进行赋值和渲染，我们实例化控制器类的时候传入模块、控制器、方法
				$controllerClass = $reflect->newInstance($moduleName, $controllerName, $actionName);
				//我们继续判断方法是否存在，我们可以用反射机制、method_exists或者is_callable
				if ($reflect->hasMethod($actionName)) {
					//我们用反射执行方法，为了方便模板处理，方法中输出的内容，我们都从缓冲区取出，使用return，然后发送出去,当然echo也可以输出，但是是直接输出，不经过处理，我们这里使用return只是演示了一下如果获取缓冲区的内容进行处理发送给浏览器，我们是在View类中进行处理输出的。
					
					//特别注意很多新手不是很理解ob输出控制函数，我们就不使用return，大家可以自己去查询常用的ob函数，ob_start、ob_get_clean、ob_implicit_flush等等，下个教学框架，我们讲容器、门面、依赖注入的时候再讲这个。
					$reflect->getMethod($actionName)->invoke($controllerClass);
				}else {
					//方法不存在，我们就抛出异常，让PHP内置异常类处理，我们就不做异常接管了
					throw new \Exception('方法' . $controller . '\\' . $actionName . '不存在！');
				}
				
			}else {
				//控制器类不存在，我们就抛出异常，让PHP内置异常类处理，我们就不做异常接管了
				throw new \Exception('控制器' . $controller . '不存在！');
			}
		}else {
			//如果模块文件夹不存在，我们就抛出异常，让PHP内置异常类处理，我们就不做异常接管了
			throw new \Exception('模块' . $module . '不存在！');
		}
	}
}
